<template>
  <div class="trainDetail">
    <a-descriptions title="模型参数" bordered>
      <template #extra>
        <a-button type="primary" @click="doEdit" v-if="!editFlag">编辑</a-button>
        <a-space v-else>
          <a-button type="primary" @click="editConfirm" ghost>确认</a-button>
          <a-button danger @click="editCancel" ghost>取消</a-button>
        </a-space>
      </template>
      <a-descriptions-item label="训练Id">{{ fileTrain?.id ?? '--' }}</a-descriptions-item>
      <a-descriptions-item label="使用模型">{{ fileTrain?.model ?? '--' }}</a-descriptions-item>
      <a-descriptions-item label="数据切分"
        >{{ fileTrain?.trainRate ?? '--' }}%</a-descriptions-item
      >
      <a-descriptions-item label="文件Id">{{ fileTrain?.fileId }}</a-descriptions-item>
      <a-descriptions-item label="数据洗牌">{{
        fileTrain?.isRefresh === 1 ? '是' : '否'
      }}</a-descriptions-item>
      <a-descriptions-item label="训练状态" :span="1">
        <a-badge status="processing" :text="fileTrain?.trainStatus" />
      </a-descriptions-item>
      <a-descriptions-item label="训练介绍" :span="1.5">
        <div style="width: 100%" v-if="!editFlag">
          {{ fileTrain?.introduction ?? '--' }}
        </div>
        <div v-else>
          <a-input v-model:value="editForm.introduction" allow-clear />
        </div>
      </a-descriptions-item>
      <a-descriptions-item label="创建时间" :span="1.5">{{
        dayjs(fileTrain?.createTime).format('YYYY-MM-DD HH:mm:ss')
      }}</a-descriptions-item>
      <a-descriptions-item label="目标列表" :span="1">
        <a-space v-for="item in fileTrain?.selectTargets" :key="item">
          第{{ Number(item) + 1 }}列
        </a-space>
      </a-descriptions-item>
      <a-descriptions-item label="特征列表">
        <a-space>
          <span v-for="item in fileTrain?.selectFeatures.sort((a, b) => a - b)" :key="item">
            第{{ Number(item) + 1 }}列,
          </span>
        </a-space>
      </a-descriptions-item>
    </a-descriptions>
    <a-divider style="margin-bottom: 16px" />

    <div style="margin-bottom: 20px; font-size: 16px"><strong>模型性能指标</strong></div>
    <a-table :columns="columns" :data-source="dataList" bordered :pagination="false"> </a-table>
    <div style="margin-bottom: 16px" />
    <a-card>
      <v-chart :option="options" style="height: 320px" />
    </a-card>
    <div style="margin-bottom: 32px" />
    <div v-if="fileTrain?.trainStatus === FILE_TRAIN_CREATE_STATUS_ENUM.SUCCESS">
      <div style="margin-bottom: 20px; font-size: 16px">
        <a-flex justify="space-between">
          <strong>模型预测</strong>
          <a-button type="primary" ghost @click="showPredictCreateModal">创建预测</a-button>
        </a-flex>

      </div>

      <a-collapse accordion>
        <a-collapse-panel :showArrow="false" v-for="item in filePredictList" :key="item.id">
          <template #extra >
            <a-space>
              <EditOutlined v-if="!editMap[item.id]" style="color: #2661a2" @click="(e) => doPredictEdit(item, e)"/>
              <a-popconfirm
                title="确定删除嘛？"
                @confirm="doPredictDelete(item)"
              >
                <DeleteOutlined style="color: red" @click="(e) => {e.stopPropagation()}"/>
              </a-popconfirm>
            </a-space>


          </template>

          <template #header>
            <a-row :wrap="false">
              <a-col flex="auto">

                <a-space style="width: 100%" v-if="!editMap[item.id]">
                  <strong> 简介： </strong>
                  <span > {{ item.introduction }} </span>
                </a-space>
                <a-flex v-else justify="space-between">
                  <a-space>
                    <strong> 简介： </strong>
                    <a-input  v-model:value="editPredictForm.introduction" allow-clear />
                  </a-space>

                  <a-space style="margin-right: 10%">
                    <a style="margin: 0" @click="(e) => doPredictEditConfirm(item ,e)">确认</a>
                    <a style="margin: 0" @click="(e) => doPredictEditCancel(item ,e)">取消</a>
                  </a-space>
                </a-flex>

              </a-col>
              <a-col flex="200px">
                <a-space>
                  <strong> 创建状态： </strong>
                  <a-badge status="processing" :text="item.predictStatus" />
                </a-space>
              </a-col>
              <a-col flex="250px">
                <strong> 创建时间： </strong>
                <span> {{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }} </span>
              </a-col>
            </a-row>
          </template>
          <a-descriptions title="基本参数信息">
            <a-descriptions-item
              v-for="variable in item.predictParams"
              :key="variable.columnNumber"
              :label="
                `第${Number(variable.columnNumber) + 1}列,` +
                featureMap[Number(variable.columnNumber) + 1]
              "
            >
              {{ variable?.param ?? '--' }}
            </a-descriptions-item>
          </a-descriptions>

          <a-descriptions title="预测结果信息">
            <a-descriptions-item label="预测状态">
              <a-tag v-if="item.predictResult?.code === 0" color="green">Success</a-tag>
              <a-tag v-else color="red">Error</a-tag>
            </a-descriptions-item>
            <a-descriptions-item label="预测信息">
              {{ item.predictResult?.message ?? '--' }}
            </a-descriptions-item>
            <a-descriptions-item :label="`${targetMap[targetColumn]} 预测结果`">
              {{ item.predictResult?.data ?? '--' }}
            </a-descriptions-item>
          </a-descriptions>
        </a-collapse-panel>
      </a-collapse>
    </div>

    <a-modal
      v-model:open="openPredictCreateModal"
      title="进行预测创建"
      @ok="handlePredictCreateConfirm"
      width="80%"
    >
      <a-descriptions title="预测简介">
        <a-descriptions-item label="简介">
          <a-input v-model:value="filePredictAddRequest.introduction" style="width: 80%" allow-clear />
        </a-descriptions-item>
      </a-descriptions>
      <a-descriptions title="基本参数信息">
        <a-descriptions-item
          v-for="(variable, index) in variablesParamsList"
          :key="variable.columnNumber"
          :label="
                `第${Number(variable.columnNumber)}列,` +
                variable.variablesName
              "
        >
          <a-input v-model:value="filePredictAddRequest.predictParams[index].param" style="width: 90%" allow-clear />
        </a-descriptions-item>
      </a-descriptions>
<!--      {{ filePredictAddRequest }}-->
    </a-modal>
    <div style="margin-bottom: 300px"/>
  </div>
</template>
<script setup lang="ts">
import { listFileVariablesVoByPageUsingPost } from '@/api/fileVariablesController.ts'
import { computed, onMounted, reactive, ref } from 'vue'
import { getFileVoByIdUsingGet } from '@/api/fileController.ts'
import { editFileTrainUsingPost, getFileTrainVoByIdUsingGet } from '@/api/fileTrainController.ts'
import dayjs from 'dayjs'
import VChart from 'vue-echarts'
import 'echarts'
import { message } from 'ant-design-vue'
import { FILE_CREATE_STATUS_ENUM, FILE_TRAIN_CREATE_STATUS_ENUM } from '@/constant/file.ts'
import {EditOutlined, DeleteOutlined} from '@ant-design/icons-vue'
import {
  addFilePredictUsingPost, deleteFilePredictUsingPost,
  editFilePredictUsingPost,
  getFilePredictVoByIdUsingGet,
  getFileVariablesListUsingPost,
  listFilePredictVoByPageUsingPost
} from '@/api/filePredictController.ts'
import COS_ENUM from '@/enums/CosEnum.ts'

const columns = [
  {
    title: '数据集',
    dataIndex: 'dataset',
    key: 'dataset',
  },
  {
    title: '准确率',
    dataIndex: 'accuracy',
    key: 'accuracy',
  },
  {
    title: '召回率',
    dataIndex: 'recall',
    key: 'recall',
  },
  {
    title: '精确率',
    dataIndex: 'precision',
    key: 'precision',
  },
  {
    title: 'F1',
    dataIndex: 'f1',
    key: 'f1',
  },
]

interface Props {
  id: string | number
}

const fileTrain = ref<API.FileTrainVO>()
const props = defineProps<Props>()

const dataList = computed(() => {
  return [
    {
      key: '1',
      dataset: '训练集',
      accuracy: fileTrain.value?.trainResult?.trainSet?.accuracy ?? 0,
      recall: fileTrain.value?.trainResult?.trainSet?.recall ?? 0,
      precision: fileTrain.value?.trainResult?.trainSet?.precision ?? 0,
      f1: fileTrain.value?.trainResult?.trainSet?.f1Score ?? 0,
    },
    {
      key: '2',
      dataset: '测试集',
      accuracy: fileTrain.value?.trainResult?.testSet?.accuracy ?? 0,
      recall: fileTrain.value?.trainResult?.testSet?.recall ?? 0,
      precision: fileTrain.value?.trainResult?.testSet?.precision ?? 0,
      f1: fileTrain.value?.trainResult?.testSet?.f1Score ?? 0,
    },
  ]
})
const getModelInfo = async () => {
  // 获取到id
  const res = await getFileTrainVoByIdUsingGet({
    id: props.id,
  })
  if (res.data.code === 0 && res.data.data) {
    fileTrain.value = res.data.data
    editForm.introduction = fileTrain.value.introduction
  }

  getFilePredict()
}

//---------- earcharts
const options = computed(() => {
  return {
    title: {
      text: '模型性能指标分析图',
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow',
      },
    },
    legend: {},
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true,
    },
    yAxis: {
      type: 'value',
      boundaryGap: [0, 0.01],
    },
    xAxis: {
      type: 'category',
      data: ['accuracy', 'recall', 'precision', 'f1-score'],
    },
    series: [
      {
        name: '测试集',
        type: 'bar',
        data: [
          fileTrain.value?.trainResult?.trainSet?.accuracy ?? 0,
          fileTrain.value?.trainResult?.trainSet?.recall ?? 0,
          fileTrain.value?.trainResult?.trainSet?.precision ?? 0,
          fileTrain.value?.trainResult?.trainSet?.f1Score ?? 0,
        ],
      },
      {
        name: '训练集',
        type: 'bar',
        data: [
          fileTrain.value?.trainResult?.testSet?.accuracy ?? 0,
          fileTrain.value?.trainResult?.testSet?.recall ?? 0,
          fileTrain.value?.trainResult?.testSet?.precision ?? 0,
          fileTrain.value?.trainResult?.testSet?.f1Score ?? 0,
        ],
      },
    ],
  }
})
const editFlag = ref(false)
const editForm = reactive<API.FileTrainEditRequest>({})
const doEdit = () => {
  editFlag.value = true
}
const editCancel = () => {
  editFlag.value = false
}
const editConfirm = async () => {
  // 获取到id
  const id = props.id
  if (id) {
    editForm.id = id
    const res = await editFileTrainUsingPost(editForm)
    if (res.data.code === 0 && res.data.data) {
      message.success('更新成功')
      getModelInfo()
    } else {
      message.error('更新失败')
    }
  }
  editFlag.value = false
}

// ---------- 预测模块

const filePredictList = ref<API.FilePredictVO[]>([])
// 搜索条件
const predictSearchParams = reactive<API.FilePredictQueryRequest>({
  current: 1,
  pageSize: 10,
  sortField: 'createTime',
  sortOrder: 'ascend',
}) // 局部更新
const getFilePredict = async () => {
  if (fileTrain.value?.trainStatus !== FILE_TRAIN_CREATE_STATUS_ENUM.SUCCESS) return

  if (props.id) {
    predictSearchParams.trainId = props.id
    // 获取到id
    const res = await listFilePredictVoByPageUsingPost(predictSearchParams)
    if (res.data.code === 0 && res.data.data) {
      filePredictList.value = res.data.data.records
      if(res.data.data.records) {
        res.data.data.records.forEach((item: API.FilePredictVO) => {
          editMap.value[item.id] = false
        })
      }

    }
  }
}
const featureMap = ref<{ [key: string]: string }>({})
const targetMap = ref<{ [key: string]: string }>({})
const editMap = ref<{ [key: string]: boolean }>({})
const targetColumn = ref(0)
const editPredictForm = reactive<API.FilePredictEditRequest>({})
const variablesParamsList = ref<API.FilePredictOutputParams[]>([])
const getVariables = async () => {
  if (props.id) {
    // 获取到id
    const res = await getFileVariablesListUsingPost({ trainId: props.id })
    if (res.data.code === 0 && res.data.data) {

      variablesParamsList.value = res.data.data.featureOutputParamsList
      // 使用 featureMap.value 来修改其值
      res.data.data.featureOutputParamsList.forEach((item: API.FilePredictOutputParams) => {
        featureMap.value[item.columnNumber] = item.variablesName
        filePredictAddRequest.predictParams?.push({
          columnNumber: Number(item.columnNumber) - 1,
          param: null
        })
      })

      res.data.data.targetOutputParamsList.forEach((item: API.FilePredictOutputParams) => {
        targetMap.value[item.columnNumber] = item.variablesName
        targetColumn.value = item.columnNumber
      })
    }
  }
}

onMounted(() => {
  getModelInfo()
  getVariables()
})

const doPredictEdit = (item, e) => {
  e.stopPropagation();
  editMap.value[item.id] = true
  editPredictForm.id = item.id
  editPredictForm.introduction = item.introduction
}

const doPredictDelete = async (item) => {
  const id = item.id
  if (id) {
    const res = await deleteFilePredictUsingPost({id: id})
    if (res.data.code === 0 && res.data.data) {
      message.success('删除成功')
      getFilePredict()
    } else {
      message.error('删除失败')
    }
  }
}

const doPredictEditCancel = (item, e) => {
  e.stopPropagation();
  editMap.value[item.id] = false
}

const doPredictEditConfirm = async (item, e) => {
  e.stopPropagation();

  const id = item.id
  if (id) {
    editPredictForm.id = id
    const res = await editFilePredictUsingPost(editPredictForm)
    if (res.data.code === 0 && res.data.data) {
      message.success('更新成功')
      getFilePredict()
    } else {
      message.error('更新失败')
    }
  }

  editMap.value[item.id] = false
}
// ------ modal

const filePredictAddRequest = reactive<API.FilePredictAddRequest>({
  introduction: "",
  predictParams: []

})
const openPredictCreateModal = ref(false)
const showPredictCreateModal = () => {
  openPredictCreateModal.value = true
}
const handlePredictCreateConfirm = async () => {
  if (fileTrain.value?.trainStatus !== FILE_TRAIN_CREATE_STATUS_ENUM.SUCCESS) return

  if (props.id) {
    filePredictAddRequest.trainId = props.id
    // 获取到id
    const res = await addFilePredictUsingPost(filePredictAddRequest)
    if (res.data.code === 0 && res.data.data) {
      message.success("创建成功")
      getFilePredict()
    }else {
      message.success("创建失败")
    }
  }


  openPredictCreateModal.value = false
}
</script>
<style scoped>
.trainDetail {
  width: 65%;
  margin: 0 auto;
}
</style>
